home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.mactech.com 2010
/
ftp.mactech.com.tar
/
ftp.mactech.com
/
machack
/
Hacks96
/
FinderUndo.sit
/
Finder Undo
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-22
|
12KB
|
657 lines
#include <A4Stuff.h>
#include "main.h"
#include "patches.h"
///////////////////////////////////////////////////////////
InitGrafProc oldInitGraf = nil;
Pack8Proc oldPack8 = nil;
MenuSelectProc oldMenuSelect = nil;
MenuKeyProc oldMenuKey = nil;
SpecialHandlerProc shpChainProc = nil;
Boolean igpatched = false;
NMRecPtr myNotification = nil;
Boolean inAESend = false;
OSType lastAction = 0;
Handle lastActionHero = nil;
enum {
kCleanUpEvent = 1,
kOpenEvent,
kCloseEvent,
kSelectEvent
};
///////////////////////////////////////////////////////////
void main(void)
{
Handle me;
EnterCodeResource();
me = Get1Resource( 'INIT', 128 );
HLock(me);
DetachResource(me);
PatchInitGraf();
ExitCodeResource();
}
inline void pstrcat( StringPtr s1, StringPtr s2 )
{
BlockMoveData( s2+1, s1+s1[0]+1, s2[0] );
s1[0] += s2[0];
}
pascal long MyMenuSelect( Point startPt )
{
long happy;
EnterCodeResource();
if (lastAction)
EnableItem( GetMenuHandle(0x0102), 1 );
else
DisableItem( GetMenuHandle(0x0102), 1 );
happy = (*oldMenuSelect)( startPt );
if (happy == 0x01020001)
{
UndoLastAction();
lastAction = 0;
if (lastActionHero) DisposeHandle( lastActionHero );
happy = 0;
}
skip:
ExitCodeResource();
return happy;
}
pascal long MyMenuKey( short ch )
{
long happy;
EnterCodeResource();
if (lastAction)
EnableItem( GetMenuHandle(0x0102), 1 );
else
DisableItem( GetMenuHandle(0x0102), 1 );
happy = (*oldMenuKey)( ch );
if ( happy == 0x01020001 ) // edit:undo -- yep, hardcoded!!
{
UndoLastAction();
lastAction = 0;
if (lastActionHero) DisposeHandle( lastActionHero );
happy = 0;
}
skip:
ExitCodeResource();
return happy;
}
void InstallBlankNotification( void )
{
NMRecPtr myNotification = (NMRecPtr) NewPtrSysClear( sizeof(NMRec));
myNotification->qLink = 0;
myNotification->qType = nmType;
myNotification->nmMark = 0;
myNotification->nmIcon = nil;
myNotification->nmSound = nil;
myNotification->nmStr = nil;
myNotification->nmResp = CustomNMRemove;
myNotification->nmRefCon = 0;
NMInstall(myNotification);
}
pascal void CustomNMRemove( NMRecPtr nmr )
{
EnterCodeResource();
NMRemove( nmr );
DisposePtr( (Ptr)nmr );
// tell the finder that it's about to start recording itself :>
{
AppleEvent recEvt = {typeNull,nil}, reply = {typeNull,nil};
ProcessSerialNumber finderPSN = { 0, kCurrentProcess };
AEDesc target = {typeNull,nil}, finderDesc = {typeNull,nil};
GetCurrentProcess( &finderPSN );
AECreateDesc( typeProcessSerialNumber, &finderPSN, sizeof(ProcessSerialNumber), &target );
AECreateAppleEvent( 'core', 'rec1', &target, kAutoGenerateReturnID, 0, &recEvt);
AEPutAttributeDesc( &recEvt, keyOriginalAddressAttr, &target );
AESend( &recEvt, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
AEDisposeDesc( &target );
AEDisposeDesc( &finderDesc );
AEDisposeDesc( &recEvt );
AEDisposeDesc( &reply );
}
ExitCodeResource();
}
void InstallAEHooks( void )
{
AEGetSpecialHandler( keyPreDispatch, (UniversalProcPtr*)&shpChainProc, false );
AEInstallSpecialHandler( keyPreDispatch, (UniversalProcPtr)MySpecialHandler, false );
}
pascal OSErr MySpecialHandler( const AppleEvent *theAppleEvent,
const AppleEvent *reply, long handlerRefcon )
{
SpecialHandlerProc localSHP;
EnterCodeResource();
if ( CAPS_KEY_IS_DOWN )
DisplayAEVT( theAppleEvent );
localSHP = shpChainProc;
ExitCodeResource();
if (localSHP)
return (*localSHP) (theAppleEvent, reply, handlerRefcon);
else
return errAEEventNotHandled;
}
OSErr MyAESend (const AppleEvent *theAppleEvent, AppleEvent *reply,
AESendMode sendMode, AESendPriority sendPriority,
long timeOutInTicks, UniversalProcPtr idleProc,
UniversalProcPtr filterProc)
{
AEKeyword junkkey, evClass, evID;
Size junksize;
EnterCodeResource();
if (inAESend) goto skip;
inAESend = true;
if (CAPS_KEY_IS_DOWN)
DisplayAEVT( theAppleEvent );
// grab the event class and id
AEGetAttributePtr( theAppleEvent, keyEventClassAttr, typeWildCard, &junkkey, &evClass, sizeof(evClass), &junksize );
AEGetAttributePtr( theAppleEvent, keyEventIDAttr, typeWildCard, &junkkey, &evID, sizeof(evID), &junksize );
switch( evClass )
{
case 'fndr':
switch (evID)
{
case 'fclu':
lastAction = kCleanUpEvent;
if (lastActionHero) DisposeHandle(lastActionHero);
lastActionHero = nil;
RememberCleanup();
break;
}
break;
case 'core':
switch (evID)
{
case 'clos':
lastAction = kCloseEvent;
if (lastActionHero) DisposeHandle(lastActionHero);
lastActionHero = nil;
RememberClose( theAppleEvent );
break;
}
break;
/* case 'aevt':
switch (evID)
{
case 'odoc':
RememberOpen( theAppleEvent );
break;
}
break;
case 'misc':
switch (evID)
{
case 'slct':
if (lastActionHero) DisposeHandle(lastActionHero);
lastActionHero = nil;
RememberSelect( theAppleEvent );
break;
}
break;
*/
}
inAESend = false;
skip:
ExitCodeResource();
}
void RememberCleanup( void )
{
short volindex = 0, fileindex;
FSSpec spec;
CInfoPBRec pb;
Ptr lap;
AppleEvent moveEvt = {typeNull,nil}, reply = {typeNull,nil};
ProcessSerialNumber finderPSN = { 0, kCurrentProcess };
AEDesc target = {typeNull,nil}, finderDesc = {typeNull,nil};
EventRecord ev;
GetCurrentProcess( &finderPSN );
AECreateDesc( typeProcessSerialNumber, &finderPSN, sizeof(ProcessSerialNumber), &target );
lastActionHero = NewHandleSys( 32768 );
HLock(lastActionHero);
lap = *lastActionHero;
while ( (spec.vRefNum = GetIndVolume(++volindex)) != 0 )
{
long saveDirID;
FlushVol( nil, spec.vRefNum );
spec.name[0] = 0;
pstrcat( spec.name, "\pDesktop Folder" );
spec.parID = 2;
if (FSpGetCatInfo( &spec, &pb, 0 ))
continue;
saveDirID = spec.parID = pb.dirInfo.ioDrDirID;
fileindex = 0;
while ( !FSpGetCatInfo( &spec, &pb, ++fileindex ) )
{
AEDesc object, object2, where;
Point point;
*(FSSpec*)lap = spec;
lap += sizeof(FSSpec);
pb.hFileInfo.ioFlFndrInfo.fdLocation.v += LMGetMBarHeight();
point = *(Point*)lap = pb.hFileInfo.ioFlFndrInfo.fdLocation;
lap += sizeof(Point);
spec.parID = saveDirID;
}
}
SetHandleSize( lastActionHero, lap - *lastActionHero );
HNoPurge( lastActionHero );
HUnlock( lastActionHero );
}
void UndoCleanup( void )
{
Ptr lap;
Size hsize = GetHandleSize( lastActionHero );
FSSpec spec;
Point point;
AppleEvent moveEvt = {typeNull,nil}, reply = {typeNull,nil};
ProcessSerialNumber finderPSN = { 0, kCurrentProcess };
AEDesc target = {typeNull,nil}, finderDesc = {typeNull,nil};
EventRecord ev;
GetCurrentProcess( &finderPSN );
AECreateDesc( typeProcessSerialNumber, &finderPSN, sizeof(ProcessSerialNumber), &target );
HLock( lastActionHero );
lap = *lastActionHero;
while ( lap < hsize + *lastActionHero )
{
AEDesc fss, item, propobj, nullobj = {typeNull,nil};
AEDesc where, property;
OSType prop = 'posn';
spec = *(FSSpec*)lap;
lap += sizeof(FSSpec);
point = *(Point*)lap;
lap += sizeof(Point);
AECreateDesc( typeFSS, &spec, sizeof(spec), &fss );
AECreateDesc( 'QDpt', &point, sizeof(Point), &where );
AECreateDesc( typeType, &prop, sizeof(prop), &property );
// given an fsspec, make an object that means "this item"
AECoerceDesc( &fss, 'obj ', &item );
*(long*)(*item.dataHandle + 20) = 'citm'; // from 'file' to 'citm'...
// now make an object that means "this property of this item"
CreateObjSpecifier( 'prop', &item, formPropertyID, &property, false, &propobj );
// lastly create and send the set-data event
AECreateAppleEvent( 'core', 'setd', &target, kAutoGenerateReturnID, 0, &moveEvt );
AEPutParamDesc( &moveEvt, '----', &propobj );
AEPutParamDesc( &moveEvt, 'data', &where );
AESend( &moveEvt, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
while (EventAvail( highLevelEventMask, &ev))
{
WaitNextEvent( highLevelEventMask, &ev, 0, nil );
if (AEProcessAppleEvent( &ev ))
DebugStr( "\perror processing the event;error d0.w" );
}
AEDisposeDesc( &fss );
AEDisposeDesc( &item );
AEDisposeDesc( &propobj );
AEDisposeDesc( &where );
AEDisposeDesc( &moveEvt );
AEDisposeDesc( &reply );
AEDisposeDesc( &property );
}
AEDisposeDesc( &target );
AEDisposeDesc( &finderDesc );
AEDisposeDesc( &moveEvt );
AEDisposeDesc( &reply );
}
void RememberClose( const AppleEvent *evt )
{
AppleEvent open;
OSType newClass = 'aevt', newID = 'odoc';
lastAction = kCloseEvent;
lastActionHero = evt->dataHandle;
HandToHand( &lastActionHero );
// modify the handle so it looks like an open event
open.descriptorType = 'aevt';
open.dataHandle = lastActionHero;
AEPutAttributePtr( &open, keyEventClassAttr, typeType, &newClass, sizeof(OSType) );
AEPutAttributePtr( &open, keyEventIDAttr, typeType, &newID, sizeof(OSType) );
// no AEDisposeDesc, please!! we need the handle!
}
void UndoClose( void )
{
AppleEvent open, reply = {typeNull,nil};
EventRecord ev;
open.descriptorType = 'aevt';
open.dataHandle = lastActionHero;
AESend( &open, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
while (EventAvail( highLevelEventMask, &ev))
{
WaitNextEvent( highLevelEventMask, &ev, 0, nil );
if (AEProcessAppleEvent( &ev ))
DebugStr( "\perror processing the event;error d0.w" );
}
AEDisposeDesc( &open );
AEDisposeDesc( &reply );
lastActionHero = nil;
lastAction = 0;
}
void RememberSelect( const AppleEvent *evt )
{
lastAction = kSelectEvent;
lastActionHero = evt->dataHandle;
HandToHand( &lastActionHero );
}
void RememberOpen( const AppleEvent *evt )
{
AppleEvent close = {'aevt',nil};
OSType newClass = 'core', newID = 'clos';
if (lastAction == kSelectEvent && lastActionHero)
{
close.dataHandle = lastActionHero;
}
else
{
if (lastActionHero) DisposeHandle(lastActionHero);
close.dataHandle = evt->dataHandle;
HandToHand( &close.dataHandle );
}
AEPutAttributePtr( &close, keyEventClassAttr, typeType, &newClass, sizeof(OSType) );
AEPutAttributePtr( &close, keyEventIDAttr, typeType, &newID, sizeof(OSType) );
lastAction = kOpenEvent;
lastActionHero = close.dataHandle;
}
void UndoOpen( void )
{
AppleEvent close = {'aevt',nil}, reply = {typeNull,nil};
EventRecord ev;
close.dataHandle = lastActionHero;
if (CAPS_KEY_IS_DOWN)
DisplayAEVT( &close );
AESend( &close, &reply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
while (EventAvail( highLevelEventMask, &ev))
{
WaitNextEvent( highLevelEventMask, &ev, 0, nil );
if (AEProcessAppleEvent( &ev ))
DebugStr( "\perror processing the event;error d0.w" );
}
AEDisposeDesc( &close );
AEDisposeDesc( &reply );
lastActionHero = nil;
lastAction = 0;
}
OSErr FSpGetCatInfo( FSSpec *spec, CInfoPBPtr pb, short index )
{
OSErr err;
pb->dirInfo.ioFVersNum = 0;
pb->dirInfo.ioCompletion = nil;
pb->dirInfo.ioNamePtr = spec->name;
pb->dirInfo.ioVRefNum = spec->vRefNum;
pb->dirInfo.ioFDirIndex = index;
pb->dirInfo.ioDrDirID = spec->parID;
err = PBGetCatInfoSync(pb);
// these fields are at the same offset for both dirInfo and hFileInfo.
spec->vRefNum = pb->dirInfo.ioVRefNum;
spec->parID = pb->dirInfo.ioDrParID;
return err;
}
short GetIndVolume( short index )
{
QHdrPtr vcbq = GetVCBQHdr();
VCB *volp = (VCB*)(vcbq->qHead);
while (volp && --index)
volp = (VCB*)volp->qLink;
if (volp) return volp->vcbVRefNum;
else return 0;
}
void UndoLastAction( void )
{
if (!lastActionHero) return;
switch (lastAction)
{
case kCleanUpEvent:
UndoCleanup();
break;
case kCloseEvent:
UndoClose();
break;
case kOpenEvent:
//UndoOpen();
break;
}
}
void DisplayAEVT( const AppleEvent *evt )
{
Str255 s,n;
*s = 0;
NumToString((long)evt,n);
pstrcat(s,"\p;aevt #");
pstrcat(s,n);
DebugStr(s);
}